#pragma once
#include <google/protobuf/service.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include <string>
#include <muduo/base/Logging.h>
#include "RpcHeader.pb.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "mprpccontroller.h"
#include "zookeeperutil.h"
class MprpcChannel:public google::protobuf::RpcChannel
{
public:
    void CallMethod(const google::protobuf::MethodDescriptor* method,
                          google::protobuf::RpcController* controller, const google::protobuf::Message* request,
                          google::protobuf::Message* response, google::protobuf::Closure* done) 
    {
        const google::protobuf::ServiceDescriptor* sd=method->service();
        std::string service_name=sd->name();
        std::string method_name=method->name();

        uint32_t arg_size=0;
        std::string arg_str;
        if(request->SerializeToString(&arg_str))
        {
            arg_size=arg_str.size();
        }
        else{
            LOG_ERROR<<"request serialize error\n";
            controller->SetFailed("request serialize error\n");
            return;
        }

        mprpc::RpcHeader header;
        header.set_service_name(service_name);
        header.set_method_name(method_name);
        header.set_args_size(arg_size);

        uint32_t header_size=0;
        std::string header_str;
        if(header.SerializeToString(&header_str))
        {
            header_size=header_str.size();
        }
        else{
            LOG_ERROR<<"header serialize error\n";
            controller->SetFailed("header serialize error\n");
            return;
        }

        //headersize+headerstr+arg_str
        std::string send_rpc_str;
        send_rpc_str.insert(0,std::string((char*)&header_size,4));
        send_rpc_str+=header_str;
        send_rpc_str+=arg_str;
        LOG_INFO<<"[INFO] : ______________________________________\n";
        LOG_INFO<<"MprpcChannel::CallMethod>>\n";
        LOG_INFO<<"header_size= "<<header_size<<"\n";
        LOG_INFO<<"service_name= "<<service_name<<"\n";
        LOG_INFO<<"method_name= "<<method_name<<"\n";
        LOG_INFO<<"arg_str= "<<arg_str<<"\n";
        LOG_INFO<<"________________________________________________\n";
        //send

        int clientfd=socket(AF_INET,SOCK_STREAM,0);
        if(-1==clientfd)
        {
            close(clientfd);
            LOG_ERROR<<"CREATE SOCKET ERROR\n";
            controller->SetFailed("CREATE SOCKET ERROR\n");
            exit(EXIT_FAILURE);
        }
        //std::string ip=MrpcApplication::getInstance().getConfig().Load("rpcserverip");
        
        //std::string port=MrpcApplication::getInstance().getConfig().Load("rpcserverport");
        ZkClient zkCli;
        zkCli.start();
        // /UserServiceRpc/Login
        std::string method_path="/"+service_name+"/"+method_name;
        std::string host_data=zkCli.GetData(method_path.c_str());
        if(host_data=="")
        {
            controller->SetFailed(method_path+"is not existed\n");
            return;
        }
        int idx=host_data.find(":");
        if(idx==-1)
        {
            controller->SetFailed(method_path+"is invalid");
            return;
        }
        std::string ip=host_data.substr(0,idx);
        uint16_t port=atoi(host_data.substr(idx+1,host_data.size()-idx).c_str());

        struct sockaddr_in server_addr;
        server_addr.sin_family=AF_INET;
        server_addr.sin_port=htons(port);
        server_addr.sin_addr.s_addr=inet_addr(ip.c_str());

        if(-1==connect(clientfd,(struct sockaddr*)&server_addr,sizeof(server_addr)))
        {
            LOG_ERROR<<"connect error\n";
            close(clientfd);
            controller->SetFailed("connect error\n");
            exit(EXIT_FAILURE);
        }
        if(-1==send(clientfd,send_rpc_str.c_str(),send_rpc_str.size(),0))
        {
            close(clientfd);
            LOG_ERROR<<"SEND ERROR\n";
            controller->SetFailed("SEND ERROR\n");
            return; 
        } 
        char recv_buf[1024]={0};
        int recv_size=0;
        if(-1==(recv_size==recv(clientfd,recv_buf,1024,0)))
        {
            close(clientfd);
            LOG_ERROR<<"recv error\n";
            controller->SetFailed("recv error\n");
            return;
        }

        //std::string response_str(recv_buf,0,recv_size);
        if(!response->ParseFromArray(recv_buf,recv_size))
        {
            close(clientfd);
            LOG_ERROR<<"RESPONSE PARSE ERROR\n";
            controller->SetFailed("RESPONSE PARSE ERROR\n");
            return;
        }

        close(clientfd);

    }   
};